﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using COFE.Core;
using System.Threading;
using System.Threading.Tasks;
using COFE.Core.Filter;
using COFE.Core.Profile;
using COFE.Core.Utils;
using NUnit.Framework;

namespace COFE.Core
{
    public class AutoEntryList : EntryListBase, IAutoEntryList
    {
        #region Constructor
        void init(IEntryFilter[] entryFilters, IOptionFilter[] optionFilters)
        {
            EntryFilters = entryFilters;
            OptionFilters = optionFilters;

            if (RootDirectories.Length == 0)
            {
                List<IEntryFilter> eFilters = new List<IEntryFilter>(entryFilters);
                eFilters.Add(new RootEntryFilter(
                    COFEShared.CurrentUserProfile.ProfileRootDirectory));
                EntryFilters = eFilters.ToArray();
            }
                
            Refresh();
        }

        void init(IDirectoryInfo[] rootDir, IEntryFilter[] entryFilters, IOptionFilter[] optionFilters)
        {
            entryFilters = entryFilters.Concat(
                from rd in rootDir select new RootEntryFilter(rd))
                .ToArray();
            init(entryFilters, optionFilters);
        }

        //public AutoEntryList(Guid id, string name,
        //   IDirectoryInfo[] rootDir, string[] entryFilterStrArray, string[] optionFilterStrArray)
        //    : base(id, name)
        //{
        //    string filterStr = String.Join(COFEShared.FilterParser.Separator,
        //        entryFilterStrArray.Concat(optionFilterStrArray));

        //    IEntryFilter[] entryFilters;
        //    IOptionFilter[] optionFilters;
        //    COFEShared.FilterParser.ParseFilter(filterStr,
        //        out entryFilters, out optionFilters);

        //    init(entryFilters, optionFilters);
        //}

        public AutoEntryList(Guid id, string name, IEntryFilter[] entryFilters, IOptionFilter[] optionFilters)
            : base(id, name)
        {
            init(entryFilters, optionFilters);
        }

        public AutoEntryList(Guid id, string name,
            IDirectoryInfo[] rootDir, IEntryFilter[] entryFilters, IOptionFilter[] optionFilters)
            : base(id, name)
        {            
            init(rootDir, entryFilters, optionFilters);
        }


        public AutoEntryList(Guid id, string name, IDirectoryInfo[] rootDirectory, string filterString)
            : base(id, name)
        {
            IDirectoryInfo _;
            IEntryFilter[] entryFilters;
            IOptionFilter[] optionFilters;
            COFEShared.FilterParser.ParseFilter(filterString, 
                out entryFilters, out optionFilters);
            init(rootDirectory, entryFilters, optionFilters);
        }

        public AutoEntryList(Guid id, string name, IDirectoryInfo rootDirectory, string filterString)
            : this(id, name, new IDirectoryInfo[] { rootDirectory }, filterString)
        {

        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="userProfile"></param>
        /// <param name="name"></param>
        /// <param name="filterString">e.g. root={Temp}\Test&amp;file=*&amp;searchoption=TopDirectoryOnly</param>
        public AutoEntryList(Guid id, string name, string filterString)
            : base(id, name)
        {            
            IEntryFilter[] entryFilters;
            IOptionFilter[] optionFilters;
            COFEShared.FilterParser.ParseFilter(filterString,
               out entryFilters, out optionFilters);
            init(entryFilters, optionFilters);
        }

        public AutoEntryList(string name, IDirectoryInfo rootDirectory, string filterString)
            : this(Guid.NewGuid(), name, rootDirectory, filterString)
        {

        }

        public AutoEntryList(string name, string filterString)
            : this(Guid.NewGuid(), name, filterString)
        {

        }

        #endregion

        #region Methods
        public virtual void Refresh()
        {
            try
            {
                Error = null;

                var optionFilters = OptionFilters.Where(
                lf => !(lf is PaginateOptionFilter) && 
                    !(lf is SortResultOptionFilter)).ToArray();                
                
                //Remove Page and Sort filter because EnumerateFSIs handles them.
                var expression = (RootDirectories).
                                SelectMany((rd) =>
                                (rd as IInternalDirectoryInfoExA).EnumerateFSIs<IFileSystemInfo>(
                                EntryFilters, optionFilters, EntryConstructionFlags.Default)
                              ).Distinct();

                //Handle them ourself.
                expression = FilterUtils2.UpdateOptionFilterExpressions(expression, OptionFilters);                
                _entryList = new ThreadSafeCachedEnumerable<IFileSystemInfo>(expression);
            }
            catch (Exception ex)
            {
                Error = ex;
            }


        }


        #endregion

        #region Data

        private ManualResetEvent _entrieslock = new ManualResetEvent(false);
        private ThreadSafeCachedEnumerable<IFileSystemInfo> _entryList;


        #endregion

        #region Public Properties

        public new StatusType Status { get { return _entryList.Caching ? StatusType.Working : Error == null ? StatusType.Completed : StatusType.Error; } }
        public ManualResetEvent EntriesLock { get { return _entrieslock; } }
        public Exception Error { get; private set; }
        public IDirectoryInfo[] RootDirectories
        {
            get
            {
                return (from rf in EntryFilters.FindFilter<RootEntryFilter>()
                        where !rf.Negative
                        select rf.Directory).ToArray();                
            }
        }
        public IEntryFilter[] EntryFilters { get; private set; }
        public IOptionFilter[] OptionFilters { get; private set; }

        public override IEnumerable<IFileSystemInfo> Entries
        {
            get
            {
                //EntriesLock.WaitOne(); 
                return _entryList;
            }
        }

        #endregion




    }
}
